package com.xb.loan.fund.impl;

import com.xb.loan.account.service.ICashService;
import com.xb.loan.account.service.constant.AccountConst;
import com.xb.loan.encryptor.crypt.Encryptor;
import com.xb.loan.encryptor.crypt.EncryptorManager;
import com.xb.loan.fund.dao.CashManualChargeDao;
import com.xb.loan.fund.dao.bean.CashManualCharge;
import com.xb.loan.fund.service.ICashManualChargeService;
import com.xb.loan.fund.service.ICashVerifyErrorService;
import com.xb.loan.fund.service.bean.CashManualChargeVO;
import com.xb.loan.fund.service.bean.CashVerifyErrorVO;
import com.xb.loan.fund.service.constant.FundConst;
import com.xb.loan.fund.service.exception.IFundServiceException;
import com.xb.loan.log.constant.IenumConstants;
import com.xb.loan.log.exception.BizException;
import com.xb.loan.usercenter.service.user.IUserBankCardService;
import com.xb.loan.usercenter.service.user.IUserService;
import com.xb.loan.usercenter.service.user.bean.UserBankCardVO;
import com.xb.loan.usercenter.service.user.bean.UserInfoVO;
import com.xb.loan.usercenter.service.user.exception.IUserServiceException;
import com.xb.loan.util.cache.redis.comm.FormatOperation;
import com.xb.loan.util.common.ObjectOperation;
import com.xb.loan.util.log.DefaultLoggerFacotry;
import com.xb.loan.util.log.LogFormatUtil;
import com.xb.loan.util.mybatis.MyTransactional;
import com.xb.loan.util.refself.BeanSelfAware;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.DecimalFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service("cashManualChargeService")
public class CashManualChargeServiceImpl implements ICashManualChargeService, BeanSelfAware {
	private static Logger logger = DefaultLoggerFacotry.getLogger(CashManualChargeServiceImpl.class);
	private CashManualChargeServiceImpl proxySelf; // ② 表示代理对象，不是目标对象

	public void setSelf(Object proxyBean) { // 通过InjectBeanSelfProcessor注入自己（目标对象）的AOP代理对象
		this.proxySelf = (CashManualChargeServiceImpl) proxyBean;
	}
	
	// 加密算法（用于本地防篡改）
	Encryptor userEncrytor = EncryptorManager.getEncryptor("user");
	
	@Autowired
	private IPartnerInfoService partnerInfoService;
	
	@Autowired
	private IUserService userService;
	
	@Autowired
	private ICashService cashService;
	
	@Autowired
    IUserBankCardService userBankCardService;
	
	@Autowired
	IEncashOrderService cashierEncashService;
	
	@Autowired
	private ICashVerifyErrorService cashVerifyErrorService;
	
	@Autowired
	private CashManualChargeDao cashManualChargeDao;
	
	@Override
	public String manualCharge(CashManualChargeVO cashManualChargeVO)
			throws BizException {
		// 接入平台需保证partnerId不为空、money>0
		PartnerInfoVO partnerInfo = partnerInfoService.selectByPrimaryKey(cashManualChargeVO.getPartnerId());
		if(partnerInfo == null){
			logger.warn(LogFormatUtil.getFormatMsg(new String[]{"module", "partnerId", "msg"},
					new Object[]{"CashManualChargeServiceImpl", cashManualChargeVO.getPartnerId(),
					IPartnerServiceException.partnerIsNotExist.getMessage()}));
			throw IPartnerServiceException.partnerIsNotExist;
		}
		
		String userId = null;
		
		if(cashManualChargeVO.getType() == FundConst.User_manualCharge){
			userId = cashManualChargeVO.getUserId();
		}else if(cashManualChargeVO.getType() == FundConst.Partner_manualCharge){
			userId = partnerInfo.getPayUserid();
		}
		
		UserInfoVO userInfoVO = userService.queryUserInfoById(userId);
		String manualChargeId = FormatOperation.assemblySeq(FundConst.PriKey_Name, FundConst.PriKey_Length);
		cashManualChargeVO.setManualchargeId(manualChargeId);
		
		cashManualChargeVO.setAccountId(userInfoVO.getAccountId());
		cashManualChargeVO.setUserId(userInfoVO.getUserId());
		cashManualChargeVO.setAccountId(userInfoVO.getAccountId());
		cashManualChargeVO.setStatus(FundConst.ChargeManualStatus_Wait);
		cashManualChargeVO.setCreateTime(FormatOperation.formatDateToYMDHms14(new Date()));
		
		// 设置支付卡名称   不为空  在填写
		UserBankCardVO userBankCardVO = userBankCardService.queryDefaultUserBankCard(userId);
		if(userBankCardVO == null){
			cashManualChargeVO.setPaycardCardname("");
		}else{
			String bankCode = userBankCardVO.getBankCode();
			
			if(bankCode != null){
				String bankName = cashierEncashService.queryBankNameByCode(bankCode);
				cashManualChargeVO.setPaycardCardname(bankName);
			}else{
				throw IUserServiceException.payCardIsNotBindsTheUser;
			}
		}

		
		// 设置签名
		String digitalSign = userEncrytor.encrypt(cashManualChargeVO.getUserId(), cashManualChargeVO.getManualchargeId(),
				cashManualChargeVO.generateKey());
		cashManualChargeVO.setDigitalSign(digitalSign);
		
		CashManualCharge cashManualCharge = ObjectOperation.convertByClasses(cashManualChargeVO,CashManualCharge.class);
		// 插入手工缴款信息
		cashManualChargeDao.insert(cashManualCharge);
		return manualChargeId;
	}
	
	@Override
	public void approveManualCharge(String manualId, int approveResult, String statusReason, int userLevel) throws BizException {
		CashManualCharge  cashManualCharge  = cashManualChargeDao.queryById(manualId);
		if(cashManualCharge == null){// 无此订单记录
			logger.warn(LogFormatUtil.getFormatMsg(new String[]{"module", "chargeOfflineId", "msg"},
					new Object[]{"CashManualChargeServiceImpl", manualId,
					IFundServiceException.ChargeManualNotExist.getMessage()}));
			throw IFundServiceException.ChargeManualNotExist;
		}else if(cashManualCharge.getStatus() != FundConst.ChargeManualStatus_Wait){// 不是待审核状态
			logger.warn(LogFormatUtil.getFormatMsg(new String[]{"module", "chargeOfflineId", "msg"},
					new Object[]{"CashManualChargeServiceImpl", manualId,
					IFundServiceException.chargeSucceed.getMessage()}));
			throw IFundServiceException.chargeSucceed;
		}
		
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("manualId", manualId);
		
		CashManualChargeVO cashManualChargeVO = ObjectOperation.convertByClasses(cashManualCharge,CashManualChargeVO.class);
		// 验签
		boolean validResult = userEncrytor.encryptValidate(cashManualChargeVO.getUserId(), cashManualChargeVO.getManualchargeId(), 
				cashManualChargeVO.generateKey(), cashManualChargeVO.getDigitalSign());
		if(!validResult){// 验签失败
			// 添加验签错误记录
			CashVerifyErrorVO cashVerifyErrorVO = generateVerifyError(cashManualCharge);
			cashVerifyErrorService.addCashVerifyError(cashVerifyErrorVO);
			// 更改线下充值记录为失败
			params.put("statusReason", IFundServiceException.localDataIsBeDistort.getMessage());
			params.put("status", FundConst.ChargeManualStatus_Fail);
			 cashManualChargeDao.updateById(params);
			
			logger.warn(LogFormatUtil.getFormatMsg(new String[]{"module", "manualId", "msg"},
					new Object[]{"CashManualChargeServiceImpl", manualId,
					IFundServiceException.localDataIsBeDistort.getMessage()}));
			throw IFundServiceException.localDataIsBeDistort;
		}
		params.put("statusReason", statusReason);
		if(approveResult == FundConst.Approve_Success){
			params.put("status", FundConst.ChargeManualStatus_Success);
			UserInfoVO userInfoVO = userService.queryUserInfoById(cashManualCharge.getUserId());
			proxySelf.approveResultTransaction(userLevel,cashManualCharge, params, userInfoVO);
		}
		else{
			params.put("status", FundConst.ChargeManualStatus_Fail);
			cashManualChargeDao.updateById(params);
		}
	}

	@MyTransactional
	public void approveResultTransaction(int userLevel,CashManualCharge cashManualCharge, Map<String, Object> params,
			UserInfoVO userInfoVO) throws BizException {
		// 修改订单状态
		cashManualChargeDao.updateById(params);
		if(userLevel == IenumConstants.UserLevel.CHANNEL.getCode()){//渠道的是手工充值
			// 加钱
			cashService.addMoney(cashManualCharge.getManualchargeId(), userInfoVO, 
					cashManualCharge.getMoney(), AccountConst.BillType_OSS_Charge, null);
		}else{//用户的是调账
			cashService.addMoney(cashManualCharge.getManualchargeId(), userInfoVO, 
					cashManualCharge.getMoney(), AccountConst.BillType_Adjust_Marketing_Costs, null);
		}
		
	}
	//生成验签错误记录信息
	private CashVerifyErrorVO generateVerifyError(CashManualCharge cashManualCharge) {
		CashVerifyErrorVO cashVerifyErrorVO = new CashVerifyErrorVO();
		cashVerifyErrorVO.setOrderId(cashManualCharge.getManualchargeId());
		cashVerifyErrorVO.setPartnerId(cashManualCharge.getPartnerId());
		cashVerifyErrorVO.setUserId(cashManualCharge.getUserId());
		cashVerifyErrorVO.setMoney(cashManualCharge.getMoney());
		cashVerifyErrorVO.setDigitalSign(cashManualCharge.getDigitalSign());
		
		cashVerifyErrorVO.setFundLimitId(FormatOperation.assemblySeq(FundConst.PriKey_Name, FundConst.PriKey_Length));
		cashVerifyErrorVO.setErrorType(FundConst.VerifyErrorType_LOCALERROR);
		cashVerifyErrorVO.setStatus(FundConst.VerifyErrorStatus_Wait);
		cashVerifyErrorVO.setOrderType(FundConst.FundType_ChargeManual);
		return cashVerifyErrorVO;
	}
	
	@Override
	public List<Map<String, Object>> queryCashChargeOfflineAccess(String partnerId, String chargeType, String statusStr, String startDate,
                                                                  String endDate, String accessSQL, int pageNum, int numPerPage) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("partnerId", partnerId);
		params.put("chargeType", chargeType);
		params.put("statusStr", statusStr);
		params.put("startDate", startDate);
		params.put("endDate", endDate);
		params.put("accessSQL", accessSQL);
		params.put("pageNum", pageNum);
		params.put("numPerPage", numPerPage);
		
		List<Map<String, Object>> list = cashManualChargeDao.queryCashManualChargeAccess(params);
		for (Map<String, Object> map : list) {
			map.put("MONEY", new DecimalFormat("0.00").format(map.get("MONEY")));
		}
		
		return list;
	}

    @Override
    public List<Map<String, Object>> statManualChargeDay(Map<String, Object> params) {
        return cashManualChargeDao.statManualChargeDay(params);
    }

	@Override
	public int queryCashChargeOfflineCountAccess(String partnerId, String chargeType, String statusStr, String startDate,
                                                 String endDate, String accessSQL) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("partnerId", partnerId);
		params.put("chargeType", chargeType);
		params.put("statusStr", statusStr);
		params.put("startDate", startDate);
		params.put("endDate", endDate);
		params.put("accessSQL", accessSQL);
		
		int intNum = cashManualChargeDao.queryCashManualChargeCountAccess(params);
		
		return intNum;
	}

	@Override
	public List<CashManualChargeVO> queryCashManualChargeList(Integer userType, String startDate,
                                                              String endDate, int pageNum, int numPerPage) {
		
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("userType", userType);
		map.put("startTime", startDate);
		map.put("endTime", endDate);
		map.put("pageNum", pageNum);
		map.put("numPerPage", numPerPage);
		List<CashManualCharge> list = cashManualChargeDao.queryCashManualChargeList(map);
		return ObjectOperation.convertByClassesList(list, CashManualChargeVO.class);
	}

}
